package com.hrsaas.ext.spider.core;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import io.netty.resolver.AbstractAddressResolver;
import io.netty.resolver.AddressResolver;
import io.netty.resolver.AddressResolverGroup;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Promise;

/**
 * Maps all host name lookups to localhost, so we can use real host names but
 * always call only our local server.
 */
class LocalhostOnlyAddressResolverGroup extends AddressResolverGroup<InetSocketAddress> {

    private final Map<EventExecutor, Res> cache = new WeakHashMap<>();

    @Override
    protected AddressResolver<InetSocketAddress> newResolver(EventExecutor ee) throws Exception {
        Res result = cache.get(ee);
        if (result == null) {
            result = new Res(ee);
            cache.put(ee, result);
        }
        return result;
    }

    static class Res extends AbstractAddressResolver<InetSocketAddress> {

        Res(EventExecutor executor) {
            super(executor, InetSocketAddress.class);
        }

        private InetAddress localhost() {
            return InetAddress.getLoopbackAddress();
        }

        @Override
        protected boolean doIsResolved(InetSocketAddress t) {
            return localhost().equals(t.getAddress());
        }

        @Override
        protected void doResolve(final InetSocketAddress addr, final Promise<InetSocketAddress> prms) throws Exception {
            super.executor().submit(new Runnable() {
                @Override
                public void run() {
                    InetAddress loc = localhost();
                    InetSocketAddress sock = new InetSocketAddress(loc, addr.getPort());
                    prms.setSuccess(sock);
                }
            });
        }

        @Override
        protected void doResolveAll(final InetSocketAddress addr, final Promise<List<InetSocketAddress>> prms) throws Exception {
            executor().submit(new Runnable() {
                @Override
                public void run() {
                    InetSocketAddress sock = new InetSocketAddress(localhost(), addr.getPort());
                    prms.setSuccess(Collections.singletonList(sock));
                }
            });
        }
    }

}
